home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Saar AMOK 2
/
Saar AMOK II - Oktober 1994 (1994)(Kreativ Marketing)(DE)[!][I-7598].iso
/
disks
/
651_700
/
662
/
playcdda
/
play.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-04
|
34KB
|
1,298 lines
/* play.c: */
#include "includes.h"
#define VERSION "1.1 (04.01.1994)"
#define HRDBLBF
#define CDDA_BUFSIZE 2368
#define SUBCHANNEL_SIZE 16
#define STD_BUFSIZE 2048
#define SENSE_LENGTH 32
#define AUDIO_BUFSIZE ((CDDA_BUFSIZE-SUBCHANNEL_SIZE)/g_compression_factor/4)
#define TOTAL_CDDA_BUFSIZE (g_buffers*2*CDDA_BUFSIZE)
#define TOTAL_AUDIO_BUFSIZE (g_buffers*2*AUDIO_BUFSIZE)
#define CDDA_STD_BUFSIZE (STD_BUFSIZE+SENSE_LENGTH)
typedef short t_bool;
typedef struct toc {
char reserved1;
unsigned char flags;
unsigned char track_number;
char reserved2;
long address;
} t_toc;
typedef enum dtype {UNKNOWNDRIVE = 0, TOSHIBA, APPLECD300} t_drivetype;
static char *TheVersion = "$VER: PlayCDDA " VERSION;
t_bool g_called_from_cli;
char g_scsi_device[80];
t_drivetype g_whatdrive = UNKNOWNDRIVE;
int g_scsi_id;
LONG g_memory_type = MEMF_CHIP;
UBYTE *g_cdda_base = NULL;
UBYTE *g_audio_base = NULL;
UBYTE *g_std_buf_base = NULL;
UBYTE *g_cdda_buf[2];
UBYTE *g_cdda_std_buf;
UBYTE *g_audio_buf[2];
struct MsgPort *g_cdda_port = NULL;
struct MsgPort *g_audio_port[2] = { NULL, NULL };
ULONG g_cdda_sigmask;
ULONG g_audio_sigmask[2];
#ifndef HRDBLBF
struct IOStdReq *g_scsireq = NULL;
t_bool g_outstanding_cdda_request = FALSE;
struct SCSICmd *g_scsicmd = NULL;
UBYTE *g_sense_data;
#else
struct IOStdReq *g_scsireq[2] = {NULL, NULL};
t_bool g_outstanding_cdda_request[2] = {FALSE, FALSE};
struct SCSICmd *g_scsicmd[2] = {NULL, NULL};
UBYTE *g_sense_data[2];
#endif
struct IOAudio *g_audioreq[2] = { NULL, NULL };
t_bool g_audio_device_open = FALSE;
long g_period;
int g_toc_length;
t_toc g_toc[100];
short g_volume = 1;
/* possible values for g_compression_factor: 2, 3, 4, 6, 7, 12, 14, 28, 49 */
unsigned short g_compression_factor = 2;
unsigned short g_buffers = 4;
/* user interface variables: */
#ifdef __SASC
extern struct Library *DOSBase;
#endif
struct Library *IconBase = NULL;
struct Library *IntuitionBase = NULL;
struct Library *GadToolsBase = NULL;
struct GfxBase *GfxBase = NULL;
struct Screen *g_screen = NULL;
void *g_visual_info = NULL;
struct Window *g_window = NULL;
struct Gadget *g_glist = NULL;
t_bool g_bye = FALSE;
char g_track_str[3] = { 0, 0, 0 };
char g_index_str[3] = { 0, 0, 0 };
char g_time_str[6] = { 0, 0, ':', 0, 0, 0 };
unsigned char g_track, g_index;
unsigned char g_minute, g_seconds;
enum gadget_ids {
GID_SAMPLING_RATE = 21,
GID_BUFFERS,
GID_VOLUME,
GID_PREV,
GID_NEXT,
GID_START,
GID_STOP,
GID_TRACK,
GID_INDEX,
GID_TIME,
/* always last: */
GID_MAX
};
struct Gadget *g_gadgets[GID_MAX];
#ifdef __SASC
void __regargs __chkabort(void)
{
}
#endif
void Cleanup_User_Interface (void)
{
if (g_window)
CloseWindow (g_window);
if (g_glist)
FreeGadgets (g_glist);
if (g_visual_info)
FreeVisualInfo (g_visual_info);
if (g_screen)
UnlockPubScreen (NULL, g_screen);
if (GfxBase)
CloseLibrary ((struct Library *) GfxBase);
if (GadToolsBase)
CloseLibrary (GadToolsBase);
if (IntuitionBase)
CloseLibrary (IntuitionBase);
}
void Cleanup_Audio (void)
{
if (g_cdda_base) {
FreeMem (g_cdda_base, TOTAL_CDDA_BUFSIZE + 15);
g_cdda_base = NULL;
}
if (g_audio_base) {
FreeMem (g_audio_base, TOTAL_AUDIO_BUFSIZE + 15);
g_audio_base = NULL;
}
if (g_audio_device_open) {
CloseDevice ((struct IORequest *) g_audioreq[0]);
g_audio_device_open = FALSE;
}
if (g_audio_port[0]) {
DeleteMsgPort (g_audio_port[0]);
g_audio_port[0] = NULL;
}
if (g_audio_port[1]) {
DeleteMsgPort (g_audio_port[1]);
g_audio_port[1] = NULL;
}
if (g_audioreq[0]) {
FreeMem (g_audioreq[0], sizeof (struct IOAudio));
g_audioreq[0] = NULL;
}
if (g_audioreq[1]) {
FreeMem (g_audioreq[1], sizeof (struct IOAudio));
g_audioreq[1] = NULL;
}
}
void Cleanup (void)
{
#ifdef HRDBLBF
int i;
#endif
Cleanup_Audio ();
if (g_std_buf_base)
FreeMem (g_std_buf_base, CDDA_STD_BUFSIZE + 15);
#ifndef HRDBLBF
if (g_scsicmd)
FreeMem (g_scsicmd, sizeof (struct SCSICmd));
if (g_scsireq) {
if (g_scsireq->io_Device) {
if (g_outstanding_cdda_request) {
AbortIO ((struct IORequest *) g_scsireq);
WaitIO ((struct IORequest *) g_scsireq);
}
CloseDevice ((struct IORequest *) g_scsireq);
}
DeleteIORequest ((struct IORequest *) g_scsireq);
}
#else
for (i = 0; i < 2; i++) {
if (g_scsicmd[i])
FreeMem (g_scsicmd[i], sizeof (struct SCSICmd));
if (g_scsireq[i]) {
if (g_scsireq[i]->io_Device) {
if (g_outstanding_cdda_request[i]) {
AbortIO ((struct IORequest *) g_scsireq[i]);
WaitIO ((struct IORequest *) g_scsireq[i]);
}
CloseDevice ((struct IORequest *) g_scsireq[i]);
}
DeleteIORequest ((struct IORequest *) g_scsireq[i]);
}
}
#endif
if (g_cdda_port)
DeleteMsgPort (g_cdda_port);
Cleanup_User_Interface ();
if (IconBase)
CloseLibrary (IconBase);
}
void Fatal_Error (char *p_message, ...)
{
va_list arg;
static struct EasyStruct req = {
sizeof (struct EasyStruct),
0,
(UBYTE *) "PlayCDDA Error",
NULL,
(UBYTE *) "Abort"
};
va_start (arg, p_message);
if (IntuitionBase) {
req.es_TextFormat = (UBYTE *) p_message;
EasyRequestArgs (NULL, &req, NULL, arg);
} else if (g_called_from_cli) {
VPrintf ((UBYTE *) p_message, (LONG *) arg);
WriteChars ((UBYTE *) "\n", 1);
} else
Alert (0x0000CDDA);
va_end (p_message);
exit (1);
}
char *Open_User_Interface (void)
{
static struct TextAttr Topaz8 = { (UBYTE *) "topaz.font", 8, 0, 0, };
struct TextFont *font;
int i, j;
static char *labels[20] = {
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
"12", "13", "14", "15", "16", "17", "18", "19", "20"
};
static char *sampling_rate_labels[] = {
"22050 bps", /* 2 */
"14700 bps", /* 3 */
"11025 bps", /* 4 */
"7350 bps", /* 6 */
"6300 bps", /* 7 */
NULL
};
static char *buffers_labels[] = {
"2",
"4",
"8",
"16",
"32",
"64",
NULL
};
static char *volume_labels[] = {
"Low",
"Medium",
"High",
NULL
};
struct NewGadget ng;
struct Gadget *gad;
int topborder;
if (!(IntuitionBase = OpenLibrary ((UBYTE *) "intuition.library", 37)))
return "cannot open intuition.library";
if (!(GadToolsBase = OpenLibrary ((UBYTE *) "gadtools.library", 37)))
return "cannot open gadtools.library";
if (!(GfxBase = (struct GfxBase *)
OpenLibrary ((UBYTE *) "graphics.library", 37)))
return "cannot open graphics.library";
/* does the font exist? */
if (!(font = OpenFont (&Topaz8)))
return "cannot open topaz 8 font";
CloseFont (font);
if (!(g_screen = LockPubScreen (NULL)))
return "cannot lock default public screen";
if (!(g_visual_info = GetVisualInfo (g_screen, TAG_END)))
return "GetVisualInfo() failed";
gad = CreateContext (&g_glist);
topborder = g_screen->WBorTop + (g_screen->Font->ta_YSize + 1);
ng.ng_Width = 20;
ng.ng_Height = 12;
ng.ng_TextAttr = &Topaz8;
ng.ng_VisualInfo = g_visual_info;
ng.ng_Flags = 0;
for (i=0; i<5; i++)
for (j=0; j<4; j++) {
ng.ng_GadgetText = (UBYTE *) labels[i*4+j];
ng.ng_GadgetID = i*4 + j + 1;
ng.ng_LeftEdge = 10 + j * 24;
ng.ng_TopEdge = topborder + 2 + i * 16;
g_gadgets[ng.ng_GadgetID] = gad =
CreateGadget (BUTTON_KIND, gad, &ng,
GA_Disabled, TRUE,
TAG_END);
}
ng.ng_GadgetID = GID_PREV;
ng.ng_GadgetText = (UBYTE *) "Prev";
ng.ng_Width = 44;
ng.ng_LeftEdge = 10;
ng.ng_TopEdge = topborder + 2 + 5 * 16;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END);
ng.ng_GadgetID = GID_NEXT;
ng.ng_GadgetText = (UBYTE *) "Next";
ng.ng_LeftEdge = 58;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END);
ng.ng_GadgetID = GID_START;
ng.ng_GadgetText = (UBYTE *) "Start";
ng.ng_LeftEdge = 120;
ng.ng_TopEdge = topborder + 2 + 4 * 16;
ng.ng_Width = 120;
ng.ng_Height = 28;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END);
ng.ng_GadgetID = GID_STOP;
ng.ng_GadgetText = (UBYTE *) "Stop";
ng.ng_LeftEdge = 250;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END);
ng.ng_GadgetText = (UBYTE *) "Sampling rate:";
ng.ng_GadgetID = GID_SAMPLING_RATE;
ng.ng_Width = 120;
ng.ng_Height = 12;
ng.ng_LeftEdge = 250;
ng.ng_TopEdge = topborder + 2;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (CYCLE_KIND, gad, &ng,
GTCY_Labels, sampling_rate_labels,
TAG_END);
ng.ng_GadgetText = (UBYTE *) "Buffers: ";
ng.ng_TopEdge += 16;
ng.ng_GadgetID = GID_BUFFERS;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (CYCLE_KIND, gad, &ng,
GTCY_Labels, buffers_labels,
GTCY_Active, 1,
TAG_END);
ng.ng_GadgetText = (UBYTE *) "Volume: ";
ng.ng_TopEdge += 16;
ng.ng_GadgetID = GID_VOLUME;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (CYCLE_KIND, gad, &ng,
GTCY_Labels, volume_labels,
GTCY_Active, (int) g_volume-1,
TAG_END);
ng.ng_GadgetID = GID_TRACK;
ng.ng_GadgetText = (UBYTE *) "Track";
ng.ng_Width = 25;
ng.ng_Height = 12;
ng.ng_LeftEdge = 170;
ng.ng_TopEdge = topborder + 2 + 3 * 16;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (TEXT_KIND, gad, &ng,
GTTX_Border, TRUE,
TAG_END);
ng.ng_GadgetID = GID_INDEX;
ng.ng_GadgetText = (UBYTE *) "Index";
ng.ng_LeftEdge = 250;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (TEXT_KIND, gad, &ng,
GTTX_Border, TRUE,
TAG_END);
ng.ng_GadgetID = GID_TIME;
ng.ng_GadgetText = (UBYTE *) "Time";
ng.ng_Width = 50;
ng.ng_LeftEdge = 320;
g_gadgets[ng.ng_GadgetID] =
gad = CreateGadget (TEXT_KIND, gad, &ng,
GTTX_Border, TRUE,
TAG_END);
if (!gad)
return "cannot create gadgets";
g_window = OpenWindowTags (NULL,
WA_Title, TheVersion + 6,
WA_Gadgets, g_glist,
WA_Left, 20,
WA_Top, 20,
WA_Width, 385,
WA_Height, topborder + 98,
WA_IDCMP, IDCMP_CLOSEWINDOW | BUTTONIDCMP | CYCLEIDCMP,
WA_PubScreen, g_screen,
WA_DragBar, TRUE,
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_Activate, TRUE,
WA_SmartRefresh, TRUE,
TAG_END);
if (!g_window)
return "cannot open window";
return NULL;
}
void Alloc_Audio (void)
{
static UBYTE whichannel[] = { 1, 2, 4, 8 };
int i;
/* allocate buffers: */
g_audio_base = AllocMem (TOTAL_AUDIO_BUFSIZE + 15, MEMF_PUBLIC | MEMF_CHIP);
if (!g_audio_base)
Fatal_Error ("cannot allocate memory");
g_cdda_base = AllocMem (TOTAL_CDDA_BUFSIZE + 15, MEMF_PUBLIC | g_memory_type);
if (!g_cdda_base)
Fatal_Error ("cannot allocate memory");
/* make the buffers quad-word aligned. This greatly helps
* performance on '040-powered systems with DMA SCSI
* controllers.
*/
g_cdda_buf[0] = (UBYTE *)(((long) g_cdda_base + 15) & ~15);
g_audio_buf[0] = (UBYTE *)(((long) g_audio_base + 15) & ~15);
g_cdda_buf[1] = g_cdda_buf[0] + g_buffers * CDDA_BUFSIZE;
g_audio_buf[1] = g_audio_buf[0] + g_buffers * AUDIO_BUFSIZE;
/* allocate message ports and IO requests: */
if (!(g_audio_port[0] = CreateMsgPort ()) ||
!(g_audio_port[1] = CreateMsgPort ()))
Fatal_Error ("cannot allocate message ports");
g_audio_sigmask[0] = (1 << g_audio_port[0]->mp_SigBit);
g_audio_sigmask[1] = (1 << g_audio_port[1]->mp_SigBit);
if (!(g_audioreq[0] = AllocMem (sizeof (struct IOAudio),
MEMF_PUBLIC | MEMF_CLEAR)) ||
!(g_audioreq[1] = AllocMem (sizeof (struct IOAudio),
MEMF_PUBLIC | MEMF_CLEAR)))
Fatal_Error ("cannot allocate memory");
/* open audio device: */
g_audioreq[0]->ioa_Request.io_Message.mn_ReplyPort = g_audio_port[0];
g_audioreq[0]->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
g_audioreq[0]->ioa_Request.io_Command = ADCMD_ALLOCATE;
g_audioreq[0]->ioa_Request.io_Flags = ADIOF_NOWAIT;
g_audioreq[0]->ioa_AllocKey = 0;
g_audioreq[0]->ioa_Data = whichannel;
g_audioreq[0]->ioa_Length = sizeof (whichannel);
if (OpenDevice ((UBYTE *) AUDIONAME, 0,
(struct IORequest *) g_audioreq[0], 0))
Fatal_Error ("cannot open audio.device\n");
g_audio_device_open = TRUE;
*(g_audioreq[1]) = *(g_audioreq[0]);
g_audioreq[0]->ioa_Request.io_Message.mn_ReplyPort = g_audio_port[0];
g_audioreq[1]->ioa_Request.io_Message.mn_ReplyPort = g_audio_port[1];
g_audioreq[0]->ioa_Data = (UBYTE *) g_audio_buf[0];
g_audioreq[1]->ioa_Data = (UBYTE *) g_audio_buf[1];
for (i=0; i<2; i++) {
struct IOAudio *req = g_audioreq[i];
req->ioa_Request.io_Command = CMD_WRITE;
req->ioa_Request.io_Flags = ADIOF_PERVOL;
req->ioa_Length = g_buffers * AUDIO_BUFSIZE;
req->ioa_Period = g_period;
req->ioa_Volume = 64;
req->ioa_Cycles = 1;
}
}
void Alloc_CDROM (void)
{
#ifdef HRDBLBF
int i;
#endif
g_std_buf_base = AllocMem (CDDA_STD_BUFSIZE + 15, MEMF_PUBLIC | MEMF_CHIP);
if (!g_std_buf_base)
Fatal_Error ("cannot allocate memory");
#ifndef HRDBLBF
g_scsicmd = AllocMem (sizeof (struct SCSICmd), MEMF_PUBLIC | MEMF_CHIP);
if (!g_scsicmd)
Fatal_Error ("cannot allocate memory");
#else
for (i = 0; i < 2; i++) {
g_scsicmd[i] = AllocMem (sizeof (struct SCSICmd), MEMF_PUBLIC | MEMF_CHIP);
if (!g_scsicmd[i])
Fatal_Error ("cannot allocate memory");
}
#endif
/* make the buffer quad-word aligned. This greatly helps
* performance on '040-powered systems with DMA SCSI
* controllers.
*/
g_cdda_std_buf = (UBYTE *)(((long) g_std_buf_base + 15) & ~15);
#ifndef HRDBLBF
g_sense_data = g_cdda_std_buf + STD_BUFSIZE;
#else
for (i = 0; i < 2; i++)
g_sense_data[i] = g_cdda_std_buf + STD_BUFSIZE;
#endif
/* allocate message ports and IO requests: */
if (!(g_cdda_port = CreateMsgPort ()))
Fatal_Error ("cannot allocate message port");
g_cdda_sigmask = (1 << g_cdda_port->mp_SigBit);
#ifndef HRDBLBF
if (!(g_scsireq = CreateIORequest (g_cdda_port,
sizeof (struct IOStdReq))))
Fatal_Error ("cannot create IO request\n");
/* open SCSI device: */
g_scsireq->io_Device = NULL;
if (OpenDevice ((UBYTE *) g_scsi_device, g_scsi_id,
(struct IORequest *) g_scsireq, 0)) {
if (g_called_from_cli)
Fatal_Error ("Cannot open \"%s\", unit %ld",
g_scsi_device, g_scsi_id);
else
Fatal_Error ("Cannot open \"%s\", unit %ld\n"
"Please edit the tooltype entries\n"
"in the PlayCDDA icon!",
g_scsi_device, g_scsi_id);
}
#else
for (i = 0; i < 2; i++) {
if (!(g_scsireq[i] = CreateIORequest (g_cdda_port,
sizeof (struct IOStdReq))))
Fatal_Error ("cannot create IO request\n");
/* open SCSI device: */
g_scsireq[i]->io_Device = NULL;
if (OpenDevice ((UBYTE *) g_scsi_device, g_scsi_id,
(struct IORequest *) g_scsireq[i], 0)) {
if (g_called_from_cli)
Fatal_Error ("Cannot open \"%s\", unit %ld",
g_scsi_device, g_scsi_id);
else
Fatal_Error ("Cannot open \"%s\", unit %ld\n"
"Please edit the tooltype entries\n"
"in the PlayCDDA icon!",
g_scsi_device, g_scsi_id);
}
}
#endif
}
void Do_SCSI_Command (UBYTE *p_command, int p_length,
short p_phase, int p_sync, int p_direction)
{
#ifndef HRDBLBF
g_scsireq->io_Length = sizeof (struct SCSICmd);
g_scsireq->io_Data = (APTR) g_scsicmd;
g_scsireq->io_Command = HD_SCSICMD;
if (p_phase == -1) {
g_scsicmd->scsi_Data = (UWORD *) g_cdda_std_buf;
g_scsicmd->scsi_Length = STD_BUFSIZE;
} else {
g_scsicmd->scsi_Data = (UWORD *) g_cdda_buf[p_phase];
g_scsicmd->scsi_Length = g_buffers * CDDA_BUFSIZE;
}
g_scsicmd->scsi_Flags = SCSIF_AUTOSENSE | p_direction;
g_scsicmd->scsi_SenseData = (UBYTE *) g_sense_data;
g_scsicmd->scsi_SenseLength = SENSE_LENGTH;
g_scsicmd->scsi_SenseActual = 0;
g_scsicmd->scsi_Command = (UBYTE *) p_command;
g_scsicmd->scsi_CmdLength = p_length;
if (p_sync) {
int i = 0;
do {
DoIO ((struct IORequest *) g_scsireq);
if (g_scsicmd->scsi_Status == 0)
return;
i++;
} while (i < 2);
Fatal_Error ("sync SCSI command failed");
} else {
SendIO ((struct IORequest *) g_scsireq);
g_outstanding_cdda_request = TRUE;
}
#else
if (p_phase == -1) {
p_phase = 0;
g_scsicmd[p_phase]->scsi_Data = (UWORD *) g_cdda_std_buf;
g_scsicmd[p_phase]->scsi_Length = STD_BUFSIZE;
} else {
g_scsicmd[p_phase]->scsi_Data = (UWORD *) g_cdda_buf[p_phase];
g_scsicmd[p_phase]->scsi_Length = g_buffers * CDDA_BUFSIZE;
}
g_scsireq[p_phase]->io_Length = sizeof (struct SCSICmd);
g_scsireq[p_phase]->io_Data = (APTR) g_scsicmd[p_phase];
g_scsireq[p_phase]->io_Command = HD_SCSICMD;
g_scsicmd[p_phase]->scsi_Flags = SCSIF_AUTOSENSE | p_direction;
g_scsicmd[p_phase]->scsi_SenseData = (UBYTE *) g_sense_data[p_phase];
g_scsicmd[p_phase]->scsi_SenseLength = SENSE_LENGTH;
g_scsicmd[p_phase]->scsi_SenseActual = 0;
g_scsicmd[p_phase]->scsi_Command = (UBYTE *) p_command;
g_scsicmd[p_phase]->scsi_CmdLength = p_length;
if (p_sync) {
int i = 0;
do {
DoIO ((struct IORequest *) g_scsireq[p_phase]);
if (g_scsicmd[p_phase]->scsi_Status == 0)
return;
i++;
} while (i < 2);
Fatal_Error ("sync SCSI command failed");
} else {
SendIO ((struct IORequest *) g_scsireq[p_phase]);
g_outstanding_cdda_request[p_phase] = TRUE;
}
#endif
}
#ifndef HRDBLBF
void Wait_CDROM_Command (void)
#else
void Wait_CDROM_Command (short p_phase)
#endif
{
ULONG sig;
#ifndef HRDBLBF
sig = Wait (SIGBREAKF_CTRL_C | g_cdda_sigmask);
if (sig & g_cdda_sigmask) {
if (CheckIO ((struct IORequest *) g_scsireq)) {
WaitIO ((struct IORequest *) g_scsireq);
g_outstanding_cdda_request = FALSE;
if (g_scsicmd->scsi_Status)
Fatal_Error ("async SCSI command failed");
}
}
if (sig & SIGBREAKF_CTRL_C)
exit (1);
#else
/* HR */
if (p_phase < 0 || p_phase > 1)
Fatal_Error ("wrong p_phase argument for Wait_CDROM_Command");
if (g_outstanding_cdda_request[p_phase] != FALSE) {
for (;;) {
sig = Wait (SIGBREAKF_CTRL_C | g_cdda_sigmask);
if (sig & g_cdda_sigmask) {
if (CheckIO ((struct IORequest *) g_scsireq[p_phase])) {
WaitIO ((struct IORequest *) g_scsireq[p_phase]);
g_outstanding_cdda_request[p_phase] = FALSE;
if (g_scsicmd[p_phase]->scsi_Status)
Do_SCSI_Command (g_scsicmd[p_phase]->scsi_Command,
g_scsicmd[p_phase]->scsi_CmdLength,
p_phase, FALSE, SCSIF_READ);
else
break;
}
}
if (sig & SIGBREAKF_CTRL_C)
exit (1);
}
}
#endif
}
void Start_CDROM_Read (short p_phase, long p_sector)
{
static UBYTE cmd[2][12] =
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}
};
if (p_phase < 0 || p_phase > 1)
Fatal_Error ("Invalid p_phase argument for Start_CDROM_Read()");
cmd[p_phase][2] = (p_sector >> 24);
cmd[p_phase][3] = ((p_sector >> 16) & 0xFF);
cmd[p_phase][4] = ((p_sector >> 8) & 0xFF);
cmd[p_phase][5] = (p_sector & 0xFF);
if (g_whatdrive == APPLECD300) {
cmd[p_phase][0] = 0xD8;
cmd[p_phase][9] = g_buffers;
Do_SCSI_Command (cmd[p_phase], 12, p_phase, FALSE, SCSIF_READ);
}
else if (g_whatdrive == TOSHIBA) {
cmd[p_phase][0] = 0x28;
cmd[p_phase][8] = g_buffers;
Do_SCSI_Command (cmd[p_phase], 10, p_phase, FALSE, SCSIF_READ);
}
}
#ifndef HRDBLBF
void Wait_CDROM_Read (void)
{
Wait_CDROM_Command ();
}
#else
void Wait_CDROM_Read (short p_phase)
{
Wait_CDROM_Command (p_phase);
}
#endif
void Update_Track_Data (short p_num)
{
g_track_str[0] = '0' + (p_num >> 4);
g_track_str[1] = '0' + (p_num & 15);
GT_SetGadgetAttrs (g_gadgets[GID_TRACK], g_window, NULL,
GTTX_Text, g_track_str, TAG_END);
g_track = p_num;
}
void Update_Index_Data (short p_num)
{
g_index_str[0] = '0' + (p_num >> 4);
g_index_str[1] = '0' + (p_num & 15);
GT_SetGadgetAttrs (g_gadgets[GID_INDEX], g_window, NULL,
GTTX_Text, g_index_str, TAG_END);
g_index = p_num;
}
void Update_Time_Data (short p_min, short p_sec)
{
g_time_str[0] = '0' + (p_min >> 4);
g_time_str[1] = '0' + (p_min & 15);
g_time_str[3] = '0' + (p_sec >> 4);
g_time_str[4] = '0' + (p_sec & 15);
GT_SetGadgetAttrs (g_gadgets[GID_TIME], g_window, NULL,
GTTX_Text, g_time_str, TAG_END);
g_minute = p_min;
g_seconds = p_sec;
}
void Convert_Buffer (short p_phase)
{
short i;
short sum;
BYTE *src = (BYTE *) g_cdda_buf[p_phase];
BYTE *dst = (BYTE *) g_audio_buf[p_phase];
BYTE *stop = src + (g_buffers * CDDA_BUFSIZE);
short skip = ((CDDA_BUFSIZE-SUBCHANNEL_SIZE)/4);
while (src < stop) {
sum = 0;
for (i=0; i<g_compression_factor; i++) {
sum += src[1] + src[3];
src += 4;
}
for (i=g_volume-1; i--;) /* this is faster than multiplication */
sum += sum;
sum /= (g_compression_factor << 1);
if (sum < -127)
sum = -127;
else if (sum > 127)
sum = 127;
*dst++ = sum;
skip -= g_compression_factor;
if (!skip) {
/* analyze Q-sub channel data: */
if (g_whatdrive == TOSHIBA) {
if (src[1] == 1) {
if (((UBYTE *) src)[2] != g_track)
Update_Track_Data (((UBYTE *) src)[2]);
if (((UBYTE *) src)[3] != g_index)
Update_Index_Data (((UBYTE *) src)[3]);
if (((UBYTE *) src)[5] != g_seconds ||
((UBYTE *) src)[4] != g_minute)
Update_Time_Data (((UBYTE *) src)[4], ((UBYTE *) src)[5]);
}
}
else if (g_whatdrive == APPLECD300) {
if (src[0] == 1) {
if (((UBYTE *) src)[1] != g_track)
Update_Track_Data (((UBYTE *) src)[1]);
if (((UBYTE *) src)[2] != g_index)
Update_Index_Data (((UBYTE *) src)[2]);
if (((UBYTE *) src)[8] != g_seconds ||
((UBYTE *) src)[7] != g_minute)
Update_Time_Data (((UBYTE *) src)[7], ((UBYTE *) src)[8]);
}
}
/* skip Q-sub channel data: */
src += SUBCHANNEL_SIZE;
skip = ((CDDA_BUFSIZE-SUBCHANNEL_SIZE)/4);
}
}
}
void Start_Play_Audio (short p_phase)
{
BeginIO ((struct IORequest *) (g_audioreq[p_phase]));
}
void Wait_Play_Audio (short p_phase)
{
ULONG sig;
sig = Wait (SIGBREAKF_CTRL_C | g_audio_sigmask[p_phase]);
if (sig & g_audio_sigmask[p_phase]) {
while (GetMsg (g_audio_port[p_phase]) == 0) ;
}
if (sig & SIGBREAKF_CTRL_C)
exit (1);
}
#define FORMAT_CDDA 0x82
#define FORMAT_STD 0x00
void Select_Block_Format (int p_format)
{
static UBYTE cmd[6] = { 0x15, 0x10, 0, 0, 12, 0 };
static UBYTE mode[12] = { 0, 0, 0, 8,
0, 0, 0, 0, 0, 0, 0, 0 };
mode[4] = p_format;
switch (p_format) {
case FORMAT_CDDA:
mode[10] = (CDDA_BUFSIZE >> 8);
mode[11] = (CDDA_BUFSIZE & 0xFF);
break;
case FORMAT_STD:
mode[10] = (STD_BUFSIZE >> 8);
mode[11] = (STD_BUFSIZE & 0xFF);
break;
}
memcpy (g_cdda_std_buf, mode, sizeof (mode));
Do_SCSI_Command (cmd, 6, -1, TRUE, SCSIF_WRITE);
}
void Read_Drive_Type (void)
{
static UBYTE cmd[6] = { 0x12, 0, 0, 0, 0, 0};
static char *applecd300string = "SONY CD-ROM CDU-8003";
static char *toshibastring = "TOSHIBA";
UBYTE *buf = g_cdda_std_buf;
#if STD_BUFSIZE > 255
cmd[4] = 0xff;
#else
cmd[4] = STD_BUFSIZE & 0xff;
#endif
Do_SCSI_Command (cmd, 6, -1, TRUE, SCSIF_READ);
if ((buf[0] & 0x1f) != 5)
Fatal_Error ("not a CD-ROM device\n");
if (!memcmp(applecd300string,
&buf[8],
strlen(applecd300string))) {
g_whatdrive = APPLECD300;
}
else if (!memcmp(toshibastring,
&buf[8],
strlen(toshibastring))) {
g_whatdrive = TOSHIBA;
}
else
Fatal_Error ("unsupported CD-ROM drive\n");
}
void Read_TOC (void)
{
static UBYTE cmd[10] = { 0x43, 0, 0, 0, 0, 0, 1,
STD_BUFSIZE >> 8, STD_BUFSIZE & 0xFF,
0, };
UBYTE *buf = g_cdda_std_buf;
Do_SCSI_Command (cmd, 10, -1, TRUE, SCSIF_READ);
g_toc_length = ((buf[0] << 8) + buf[1] - 2) / 8;
memcpy (g_toc, buf + 4, 8 * g_toc_length);
}
void Enable_Track_Buttons (void)
{
int i, foo;
for (i=0; i<g_toc_length; i++) {
/* ENFORCER HIT, because if () {statement} is executed, even
* though expression evalutes to 0 with SAS/C 6.50.
* (added foo to avoid problem <HR>)
*/
foo = g_toc[i].track_number;
if (foo <= 20 &&
!(g_toc[i].flags & 4)) {
GT_SetGadgetAttrs (g_gadgets[g_toc[i].track_number],
g_window, NULL,
GA_Disabled, FALSE,
TAG_END);
}
}
}
long Track_Address (int p_track)
{
int i;
for (i=0; i<g_toc_length; i++) {
if (g_toc[i].track_number == p_track) {
if (g_toc[i].flags & 4)
return -1;
return g_toc[i].address;
}
}
return -1;
}
int First_Track (void)
{
int i;
for (i=0; i<g_toc_length; i++) {
if (g_toc[i].track_number != 0xAA &&
!(g_toc[i].flags & 4))
return g_toc[i].track_number;
}
return 0;
}
long Next_Track (int p_offset)
{
int track = (g_track >> 4) * 10 + (g_track & 15);
long res;
track += p_offset;
res = Track_Address (track);
return res == -1 ? Track_Address (track - p_offset) : res;
}
void NTSC_or_PAL (void)
{
if (GfxBase->DisplayFlags & PAL)
g_period = 3546895 / (44100 / g_compression_factor);
else
g_period = 3579545 / (44100 / g_compression_factor);
}
void Init_Idle_Mode (void)
{
GT_SetGadgetAttrs (g_gadgets[GID_STOP], g_window, NULL,
GA_Disabled, TRUE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_START], g_window, NULL,
GA_Disabled, FALSE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_SAMPLING_RATE], g_window, NULL,
GA_Disabled, FALSE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_BUFFERS], g_window, NULL,
GA_Disabled, FALSE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_PREV], g_window, NULL,
GA_Disabled, TRUE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_NEXT], g_window, NULL,
GA_Disabled, TRUE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_TRACK], g_window, NULL,
GTTX_Text, "", TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_INDEX], g_window, NULL,
GTTX_Text, "", TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_TIME], g_window, NULL,
GTTX_Text, "", TAG_END);
}
void Init_Play_Mode (void)
{
GT_SetGadgetAttrs (g_gadgets[GID_STOP], g_window, NULL,
GA_Disabled, FALSE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_START], g_window, NULL,
GA_Disabled, TRUE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_SAMPLING_RATE], g_window, NULL,
GA_Disabled, TRUE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_BUFFERS], g_window, NULL,
GA_Disabled, TRUE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_PREV], g_window, NULL,
GA_Disabled, FALSE, TAG_END);
GT_SetGadgetAttrs (g_gadgets[GID_NEXT], g_window, NULL,
GA_Disabled, FALSE, TAG_END);
g_track = g_index = g_minute = g_seconds = 0xFF;
}
int Get_Intui_Message (long *p_sec_no)
{
struct IntuiMessage *imsg;
struct Gadget *gad;
ULONG class;
UWORD code;
if (imsg = GT_GetIMsg (g_window->UserPort)) {
class = imsg->Class;
code = imsg->Code;
gad = (struct Gadget *) imsg->IAddress;
GT_ReplyIMsg (imsg);
switch (class) {
case IDCMP_CLOSEWINDOW: {
g_bye = TRUE;
return TRUE;
}
case IDCMP_GADGETUP:
if (gad->GadgetID <= 20)
*p_sec_no = Track_Address (gad->GadgetID);
else if (gad->GadgetID == GID_STOP)
return TRUE;
else if (gad->GadgetID == GID_VOLUME)
g_volume = code + 1;
else if (gad->GadgetID == GID_PREV)
*p_sec_no = Next_Track (-1);
else if (gad->GadgetID == GID_NEXT)
*p_sec_no = Next_Track (+1);
break;
default:
break;
}
}
return FALSE;
}
#define INC_SEC(ptr,inc) *(ptr) += (inc)
void main (int argc, char *argv[])
{
short i=0;
long sec_no;
char *err;
struct IntuiMessage *imsg;
t_bool done;
struct Gadget *gad;
ULONG class;
UWORD code;
char *error_msg = NULL;
atexit (Cleanup);
g_called_from_cli = (argc > 0);
if (g_called_from_cli) {
static UBYTE* template = (UBYTE *)
"DEVICE/A,UNIT/A/N,CHIP/S,FAST/S,DMA/S,ANY/S,"
"LOW/S,MEDIUM/S,HIGH/S";
enum Arg {
ARG_DEVICE,
ARG_UNIT,
ARG_CHIP,
ARG_FAST,
ARG_DMA,
ARG_ANY,
ARG_LOW,
ARG_MEDIUM,
ARG_HIGH,
ARGCOUNT
};
static LONG args[ARGCOUNT];
struct RDArgs* rd;
if (rd = ReadArgs (template, args, NULL)) {
int cnt_mem = 0;
int cnt_vol = 0;
strcpy (g_scsi_device, (char*) (args[ARG_DEVICE]));
g_scsi_id = args[ARG_UNIT];
if (args[ARG_CHIP])
g_memory_type = MEMF_CHIP, cnt_mem++;
if (args[ARG_FAST])
g_memory_type = MEMF_FAST, cnt_mem++;
if (args[ARG_DMA])
g_memory_type = MEMF_24BITDMA, cnt_mem++;
if (args[ARG_ANY])
g_memory_type = MEMF_ANY, cnt_mem++;
if (args[ARG_LOW])
g_volume = 1, cnt_vol++;
if (args[ARG_MEDIUM])
g_volume = 2, cnt_vol++;
if (args[ARG_HIGH])
g_volume = 3, cnt_vol++;
FreeArgs (rd);
if (cnt_mem > 1)
Fatal_Error ("Only ONE memory option may be used!");
if (cnt_vol > 1)
Fatal_Error ("Only ONE volume option may be used!");
} else
Fatal_Error ("Args do not match template %s\n", template);
strcpy (g_scsi_device, argv[1]);
g_scsi_id = atoi (argv[2]);
} else {
char *str;
UBYTE **toolarray;
struct WBStartup *wbench_msg;
struct DiskObject *dobj;
if (!(IconBase = OpenLibrary ((UBYTE *) "icon.library", 37)))
exit (1);
wbench_msg = (struct WBStartup *) argv;
dobj = GetDiskObject ((UBYTE *) wbench_msg->sm_ArgList->wa_Name);
if (!dobj)
exit (1);
toolarray = (UBYTE **) dobj->do_ToolTypes;
str = (char *) FindToolType (toolarray, (UBYTE *) "DEVICE");
if (!str)
error_msg = "Tool type DEVICE is missing";
strcpy (g_scsi_device, str);
str = (char *) FindToolType (toolarray, (UBYTE *) "UNIT");
if (!str)
error_msg = "Tool type UNIT is missing";
g_scsi_id = atoi (str);
str = (char *) FindToolType (toolarray, (UBYTE *) "MEMORY");
if (str) {
if (strcmp (str, "CHIP") == 0)
g_memory_type = MEMF_CHIP;
else if (strcmp (str, "FAST") == 0)
g_memory_type = MEMF_FAST;
else if (strcmp (str, "DMA") == 0)
g_memory_type = MEMF_24BITDMA;
else if (strcmp (str, "ANY") == 0)
g_memory_type = MEMF_ANY;
else
error_msg = "Invalid MEMORY tool type";
}
str = (char *) FindToolType (toolarray, (UBYTE *) "VOLUME");
if (str) {
if (strcmp (str, "LOW") == 0)
g_volume = 1;
else if (strcmp (str, "MEDIUM") == 0)
g_volume = 2;
else if (strcmp (str, "HIGH") == 0)
g_volume = 3;
else
error_msg = "Invalid VOLUME tool type";
};
FreeDiskObject (dobj);
}
err = Open_User_Interface ();
if (err)
Fatal_Error ("ERROR: %s", err);
if (error_msg)
Fatal_Error ("%s", error_msg);
Alloc_CDROM ();
Read_Drive_Type ();
if (g_whatdrive == TOSHIBA)
Select_Block_Format (FORMAT_CDDA);
Read_TOC ();
Enable_Track_Buttons ();
if (!First_Track ())
Fatal_Error ("This is no audio disk");
while (!g_bye) {
Init_Idle_Mode ();
done = FALSE;
while (!done) {
Wait (1 << g_window->UserPort->mp_SigBit);
while (imsg = GT_GetIMsg (g_window->UserPort)) {
class = imsg->Class;
code = imsg->Code;
gad = (struct Gadget *) imsg->IAddress;
GT_ReplyIMsg (imsg);
switch (class) {
case IDCMP_CLOSEWINDOW:
Select_Block_Format (FORMAT_STD);
exit (0);
case IDCMP_GADGETUP:
if (gad->GadgetID <= 20) {
sec_no = Track_Address (gad->GadgetID);
done = TRUE;
} else if (gad->GadgetID == GID_START) {
sec_no = Track_Address (First_Track ());
done = TRUE;
} else if (gad->GadgetID == GID_VOLUME)
g_volume = code + 1;
else if (gad->GadgetID == GID_SAMPLING_RATE) {
static short factors[] = { 2, 3, 4, 6, 7 };
g_compression_factor = factors[code];
} else if (gad->GadgetID == GID_BUFFERS) {
static short buffers[] = { 2, 4, 8, 16, 32, 64 };
g_buffers = buffers[code];
}
break;
default:
break;
}
}
}
Init_Play_Mode ();
NTSC_or_PAL ();
Alloc_Audio ();
Start_CDROM_Read (0, sec_no);
#ifndef HRDBLBF
Wait_CDROM_Read ();
#else
Wait_CDROM_Read (0);
#endif
INC_SEC (&sec_no, g_buffers);
Start_CDROM_Read (1, sec_no);
Convert_Buffer (0);
#ifndef HRDBLBF
Wait_CDROM_Read ();
#else
Wait_CDROM_Read (1);
#endif
Convert_Buffer (1);
Start_Play_Audio (0);
Start_Play_Audio (1);
INC_SEC (&sec_no, g_buffers);
Start_CDROM_Read (0, sec_no);
for (;;) {
/* HERE: scsi-request i is active,
play-audio i is active and
play-audio 1-i is queued */
if (Get_Intui_Message (&sec_no))
break;
#ifndef HRDBLBF
Wait_CDROM_Read ();
#else
Wait_CDROM_Read (i);
#endif
INC_SEC (&sec_no, g_buffers);
Start_CDROM_Read (1-i, sec_no);
Wait_Play_Audio (i);
Convert_Buffer (i);
Start_Play_Audio (i);
i = 1-i;
}
#ifndef HRDBLBF
Wait_CDROM_Read ();
#else
Wait_CDROM_Read (0);
Wait_CDROM_Read (1);
#endif
Wait_Play_Audio (i);
Wait_Play_Audio (1-i);
Cleanup_Audio ();
}
if (g_whatdrive == TOSHIBA)
Select_Block_Format (FORMAT_STD);
exit (0);
}